aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/send/ecash/[request]/+page.svelte
blob: f014d1b680c139fd1a40e19aeea57c5d481e1bec (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<script lang="ts">
  import { goto } from "$app/navigation";
  import { focus, fail, post } from "$lib/utils";
  import { applyAction, deserialize } from "$app/forms";
  import { t } from "$lib/translations";
  import { enhance } from "$app/forms";
  import Amount from "$comp/Amount.svelte";
  import Numpad from "$comp/Numpad.svelte";
  import Spinner from "$comp/Spinner.svelte";
  import { rate, pin } from "$lib/store";
  import { wrapEvent } from "nostr-tools/nip17";
  import { getPrivateKey, sign, send } from "$lib/nostr";
  import { getDecodedToken } from "@cashu/cashu-ts";
  import type { PaymentRequestPayload } from "@cashu/cashu-ts";
  import { AbstractSimplePool } from "nostr-tools/abstract-pool";

  const alwaysTrue: any = (t: Event) => {
    t[Symbol("verified")] = true;
    return true;
  };

  export const pool = new AbstractSimplePool({ verifyEvent: alwaysTrue });

  const { data, form } = $props();

  let formElement = $state();
  let submitting = $state();
  let submit = async (e) => {
    e.preventDefault();
    submitting = true;

    try {
      let { pid, token } = await post("/ecash/mint", { amount });
      let { proofs } = getDecodedToken(token);
      let { id, mints, unit = "" } = req;
      let mint = mints[0];

      const payload = {
        id,
        mint,
        unit,
        proofs,
      };

      if (type === "nostr") {
        let event = wrapEvent(
          await getPrivateKey(user),
          { publicKey: recipient.pubkey },
          JSON.stringify(payload),
        );

        await Promise.any(pool.publish(recipient.relays, event));
      } else if (type === "post") {
        await post("/ecash/post", { target, payload });
      }

      goto(`/sent/${pid}`);
    } catch (e) {
      console.log(e);
      fail(e.message);
    }

    submitting = false;
  };

  let { recipient, req, user, type, target } = $derived({
    ...data,
    ...form,
  });
  let { currency } = $derived(user);
  let a = $state();
  let next = $state();
  let toggle = () => (show = !show);
  let amount = $derived(form?.amount || data.req.amount);

  $effect(() => ($rate ||= data.rate));
  $effect(() => form && (submitting = false));
</script>

<div class="container px-4 max-w-xl mx-auto text-center space-y-2">
  {#if amount}
    {#if form?.message}
      <div class="text-red-600 text-center">
        {$t(form.message)}
      </div>
    {/if}

    <div>
      <h1 class="text-lg text-secondary">
        {$t("payments.send")}
      </h1>

      <Amount {amount} rate={$rate} {currency} />
    </div>

    <div class="text-xl">
      <span class="text-secondary">{$t("payments.to")}</span>
      <span class="break-words font-semibold">{recipient.name}</span>
    </div>

    <form onsubmit={submit} class="space-y-2" bind:this={formElement}>
      <input name="amount" value={amount} type="hidden" />
      <input name="pin" value={$pin} type="hidden" />

      <button
        type="submit"
        class="btn btn-primary"
        disabled={submitting}
        use:focus
      >
        {#if submitting}
          <Spinner />
        {:else}
          {$t("payments.send")}
        {/if}
      </button>
    </form>
  {:else}
    <form method="POST" action="?/setAmount" class="space-y-2" use:enhance>
      <input type="hidden" value={a} name="amount" />
      <input name="rate" value={$rate} type="hidden" />

      <Numpad bind:amount={a} {currency} bind:rate={$rate} submit={next} />
      <button type="submit" class="btn" bind:this={next}
        >{$t("payments.next")}</button
      >
    </form>
  {/if}
</div>